Speed up clearing downstream tasks on large Dags - #71203
Open
ColtenOuO wants to merge 1 commit into
Open
Conversation
partial_subset decided whether each downstream relative was already among the matched tasks by scanning a list, once per relative. Both the list and the relative count grow with the Dag, so the check cost O(matched x relatives) -- cubic in the task count for a Dag whose tasks mostly reach one another, which is exactly what clearing with downstream on a deep Dag looks like. Task ids are unique within a Dag, and the relatives are the same objects the matched list already holds, so the identity scan answers the same question as a constant-time lookup against a set of those ids.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
partial_subsetwalks the downstream relatives of every matched task, and for each oneasks whether that relative is itself among the matched tasks:
matched_tasksis a list becauseSerializedBaseOperatorsets__hash__ = None, so theoperators cannot go in a set at all. Its
__eq__returnsNotImplemented, which makesinfall back to an identity scan — cheap per comparison, but stillO(len(matched_tasks))per relative.
That puts the check at
O(matched x relatives). Both factors grow with the Dag, so on a Dagwhose tasks mostly reach one another the whole call goes cubic in the task count.
Task ids are unique within a Dag, and the relatives
get_flat_relativesyields are the veryobjects
matched_tasksholds, so the identity scan and a set lookup ontask_idanswer thesame question. The set lookup is constant time, dropping the check to
O(matched+ relatives).Although it seems like a small change, I looked into it further and gathered some data. Here's what I found:
What drives the cost
The improvement tracks the number of downstream relatives, which is set by the Dag's
depth, not its task count. Four shapes, each measured at the same three task counts.
Chain
Every task reaches every later one, so relatives grow as$\frac{N(N-1)}{2}$ . This is the ceiling.
Doubling the task count multiplies the old timing by ~7.6 and the new one by ~3.6 —
cubic against quadratic.
Layered
Width does not help on its own. Connecting each layer fully to the next still lets every$\frac{N^2}{2}$ and the timings
task reach everything downstream of it, so relatives stay near
land almost on top of the chain.
Parallel chains
Splitting one Dag into$K$ independent pipelines divides the relatives by $K$ — several
unrelated flows sharing a Dag file is a common shape, and it still gains meaningfully.
Fan-out
The control. One task has relatives and the rest have none, so there is almost no
scanning to remove and the change should do nothing — which is what it does.
Reading the four together
The speedup ranks exactly with the relative count — 79,800 → 13.9x, 76,000 → 11.3x,
7,800 → 6.7x, 399 → 1.8x — and within each shape the ratio doubles as the task count
doubles: 3.1x, 6.5x, 13.9x on the chain. That is what one extra linear factor looks like,
and the flat fan-out row is the check that the gain is coming from the scan rather than
from the benchmark.
Benchmark script
Result